import { getToken, generateRandomId } from '@/utils';
import QAxios from './request/index';
import LoadingInstance from './request/loading';
import { BASE_URL, TIME_OUT, SUCCESS_STATUS_CODES, ERR_RETRY_AND_DELAY } from './request/config';
import { errorHandle, errorReqTimeout, handleErrorMessage } from './request/errorHandle';
import { removePending, setCancelConfig } from './request/cancelToken';
import { codeCollection, removeEmptyAttr } from './request/handle';
import { message } from '@/components/q-message/message';
import type { QsRequestHeaderType } from './request/type';
import type { AxiosRequestHeaders } from 'axios'; // TODO: 删除

const excludeCancelUrl = ['/classSystem/generate/working/calendar'];

// 判断是否隐藏Loading
const isHideLoading = (hide: QsRequestHeaderType['hideLoading']) => hide === undefined || !+hide;

// TODO: 删除
const deviceId = generateRandomId();
const setHeaders = (header: AxiosRequestHeaders) => {
    header['Client-Type'] = 'PLATFORM_CONSOLE';
    header['Shop-Id'] = '0';
    header['Device-Id'] = deviceId;
    header['Platform'] = 'PC';
};
// TODO: 删除

const qAxios: QAxios = new QAxios({
    baseURL: BASE_URL,
    timeout: TIME_OUT,
    interceptors: {
        requestInterceptor: async config => {
            // 处理请求参数中的空字符串;
            config.params = removeEmptyAttr(config.params);
            // 处理请求参数中的空字符串
            config.data = removeEmptyAttr(config.data);

            if (!excludeCancelUrl.includes(config.url ?? '')) {
                removePending(config);
                setCancelConfig(config);
            }

            // 登录流程控制中，根据本地是否存在token判断用户的登录情况
            // 但是即使token存在，也有可能token是过期的，所以在每次的请求头中携带token
            // 后台根据携带的token判断用户的登录情况，并返回给我们对应的状态码
            // 而后我们可以在响应拦截器中，根据状态码进行一些统一的操作。

            const token = getToken();
            if (token) {
                config.headers['Authorization'] = `${token}`;
            }

            setHeaders(config.headers); // TODO: 删除

            // 所有的请求都添加loading
            if (isHideLoading(config.headers.hideLoading)) {
                LoadingInstance.showLoading(config.headers.loadingTarget);
            }

            return config;
        },
        requestInterceptorCatch: err => {
            //判断当前请求是否设置了不显示Loading
            if (isHideLoading(err.config.headers.hideLoading)) {
                LoadingInstance.hideLoading();
            }

            message.error(err.data.error.message);
            return Promise.reject(err.data.error.message);
        },
        responseInterceptor: async res => {
            removePending(res.config);

            //判断当前请求是否设置了不显示Loading（不显示自然无需隐藏）
            if (isHideLoading(res.config.headers.hideLoading)) {
                LoadingInstance.hideLoading();
            }

            const { status, data } = res;

            if (SUCCESS_STATUS_CODES.includes(status)) {
                if (codeCollection[data.code]) {
                    return codeCollection[data.code](res);
                } else {
                    handleErrorMessage(res);
                }
            }

            return Promise.reject(res);
        },
        responseInterceptorCatch: async err => {
            const { response: res } = err;

            // 取消请求
            if (qAxios.isCancel(err)) {
                LoadingInstance.hideLoading();
                return;
            }

            if (res) {
                if (
                    !err.config.headers.hideMsg && // 非隐藏错误提示状态
                    err.config.__retryCount >= ERR_RETRY_AND_DELAY[0] // 重试次数完成在做对应的报错处理
                )
                    errorHandle(res.status, res.data.msg || res.data.statusText);

                try {
                    // 超时重新请求
                    await errorReqTimeout(qAxios, err, res);
                } finally {
                    // 等所有尝试请求结束后，判断当前请求是否设置了不显示Loading（不显示自然无需隐藏）
                    if (isHideLoading(err.config.headers.hideLoading)) {
                        LoadingInstance.hideLoading();
                    }
                    removePending(err.config);
                }
            } else {
                // 处理断网的情况
                // eg:请求超时或断网时，更新state的network状态
                // network状态在app.vue中控制着一个全局的断网提示组件的显示隐藏
                // 后续增加断网情况下做的一些操作
                // store.commit('networkState', false);
                LoadingInstance && LoadingInstance.hideLoading();
                handleErrorMessage(err, `网络出错，请检查您的网络`);
            }
            return Promise.reject(err);
        }
    }
});

export default Object.freeze(qAxios);
